﻿using FreeImageAPI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace topng
{
    internal class Tonemap
    {
        public double expo = 1.0;
        public double gamma = 1.0;
    }

    class Program
    {
        static double G_Gamma = 1.0f;
        public static float ReadFormPtr(IntPtr ptr)
        {
            var sr = (uint)Marshal.ReadInt32(ptr);
            byte[] bs = BitConverter.GetBytes(sr);
            float r = BitConverter.ToSingle(bs, 0);

            return r;
        }

        private static double toneMap(Tonemap tm, double value)
        {
            return tm.expo * Math.Pow(value, tm.gamma);
        }

        //string[] args = new string[] { "Lightmap-0_comp_light.exr" ,"Lightmap-0_comp_light_dir.png"};

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //Program.SaveExrToPng(args[0], args[0] + ".png");

            if (args.Length == 0)
            {
                Console.WriteLine("参数为空");
                return;
            }

            string gammaStr = args[0];
            if (string.IsNullOrEmpty(gammaStr))
            {
                Console.WriteLine("参数异常  参数长度：" + args.Length);
                return;
            }
            double gammaArg = double.Parse(gammaStr);
            if (double.IsNaN(gammaArg))
            {
                Console.WriteLine("参数异常 gammaStr：" + gammaStr);
                return;
            }
            G_Gamma = gammaArg;

            for (int i = 1; i < args.Length; i += 2)
            {
                Console.WriteLine("输入对象=>" + args[i]);   //完整文件路径
                Console.WriteLine("输出对象=>" + args[i + 1]);


                string srcfile = args[i];
                string destfile = args[i + 1];
                FreeImageBitmap freeImageBitmap = FreeImageBitmap.FromFile(srcfile);
                {
                    //传统输出 rgbe编码？
                    //这到底是个啥
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, srcrgbe);
                    buffer_rgbe.SaveAsPng(destfile);

                    Console.WriteLine("maxcolor=" + maxcolor);
                }

                {
                    //检验一下rgbe
                    //这到底是个啥
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, srcrgbe_check);
                    buffer_rgbe.SaveAsPng(destfile + "_check.png");
                }
                //没有发现问题


                ////下面所有的处理过程都加了 srcrgbe_check,这会重复一次encode decode，把损失叠上去
                //{ //AB输出 a图映射0~1，b图映射1~2

                //    var buffer = new ExportBuffer();
                //    buffer.ParseBitmap(freeImageBitmap, NoChange, DecOne);
                //    buffer.SaveAsPng(destfile + "_a.png", destfile + "_b.png");
                //}

                //{ //AB输出 a图映射0~2.5，b图映射2.5~5.0

                //    var buffer = new ExportBuffer();
                //    buffer.ParseBitmap(freeImageBitmap, NoChange_2_5, DecOne_2_5);
                //    buffer.SaveAsPng(destfile + "_ffa.png", destfile + "_ffb.png");
                //    //shader还原方法 (a+b) *2.5
                //}
                //{
                //    var buffer = new ExportBuffer();
                //    buffer.ParseBitmap(freeImageBitmap, NoChange, null);
                //    //自定义float16格式，为了便于js读取
                //    buffer.SaveAsRaw16(destfile + ".raw");
                //}
                //{
                //    var buffer = new ExportBuffer();
                //    buffer.ParseBitmap(freeImageBitmap, NoChange, null);
                //    //自定义float16格式，为了便于js读取
                //    buffer.SaveAsRaw32(destfile + ".raw32");
                //}


                ///////////////////////////////////////////////
                ///下面这些是正经的输出
                { //AB输出 a图映射0~1，b图映射1~2

                    var buffer = new ExportBuffer();
                    buffer.ParseBitmap(freeImageBitmap, RealRaw, RealRawDec);
                    buffer.SaveAsPng(destfile + "_a.png", destfile + "_b.png");
                }
                {
                    var buffer = new ExportBuffer();
                    buffer.ParseBitmap(freeImageBitmap, RealRaw, null);
                    //自定义float16格式，为了便于js读取
                    buffer.SaveAsRaw16(destfile + ".raw");
                }
                {
                    var buffer = new ExportBuffer();
                    buffer.ParseBitmap(freeImageBitmap, RealRaw, null);
                    //自定义float16格式，为了便于js读取
                    buffer.SaveAsRaw32(destfile + ".raw32");
                }

                //////////////////////////////////////////////////
                ///rgbe线性优化
                ///decode_hdr(vec4 color)
                ///{
                ///     float power = a * 255.0;
                ///     return color.xyz*power
                ///}
                {
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, rgbefix);
                    buffer_rgbe.SaveAsPng(destfile + "_fix.png");
                }

                {
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, rgbefix_check);
                    buffer_rgbe.SaveAsPng(destfile + "_fix_check.png");
                }
                ///rgbe指数降低优化
                ///这种优并降低了指数范围 0 到 +8
                ///decode_hdr(vec4 color)
                ///{
                ///     float power = pow(2.0,a * 8.0);
                ///     return color.xyz*power
                ///}
                {
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, rgbefix_2);
                    buffer_rgbe.SaveAsPng(destfile + "_fix2.png");
                }

                {
                    var buffer_rgbe = new ExportBuffer();
                    buffer_rgbe.ParseBitmap(freeImageBitmap, rgbefix2_check);
                    buffer_rgbe.SaveAsPng(destfile + "_fix2_check.png");
                }
            }
        }

        static void NoChange(ref float r, ref float g, ref float b, ref float a)
        {
            srcrgbe_check(ref r, ref g, ref b, ref a);

            //r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            //g = (float)Math.Pow(g, G_Gamma);
            //b = (float)Math.Pow(b, G_Gamma);

            a = 1.0f;
        }
        static void RealRaw(ref float r, ref float g, ref float b, ref float a)
        {
            r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            g = (float)Math.Pow(g, G_Gamma);
            b = (float)Math.Pow(b, G_Gamma);

            a = 1.0f;
        }
        static void RealRawDec(ref float r, ref float g, ref float b, ref float a)
        {
            r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            g = (float)Math.Pow(g, G_Gamma);
            b = (float)Math.Pow(b, G_Gamma);
            r = r - 1.0f;
            g = g - 1.0f;
            b = b - 1.0f;

            a = 1.0f;
        }
        static void DecOne(ref float r, ref float g, ref float b, ref float a)
        {
            srcrgbe_check(ref r, ref g, ref b, ref a);

            //r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            //g = (float)Math.Pow(g, G_Gamma);
            //b = (float)Math.Pow(b, G_Gamma);

            r = r - 1.0f;
            g = g - 1.0f;
            b = b - 1.0f;

            a = 1.0f;
        }

        static void NoChange_2_5(ref float r, ref float g, ref float b, ref float a)
        {
            srcrgbe_check(ref r, ref g, ref b, ref a);

            r = r * 0.4f;
            g = g * 0.4f;
            b = b * 0.4f;

            a = 1.0f;
        }
        static void DecOne_2_5(ref float r, ref float g, ref float b, ref float a)
        {
            srcrgbe_check(ref r, ref g, ref b, ref a);

            r = r * 0.4f;
            g = g * 0.4f;
            b = b * 0.4f;

            r = r - 1.0f;
            g = g - 1.0f;
            b = b - 1.0f;

            a = 1.0f;
        }
        static double maxcolor = 0;
        static void srcrgbe(ref float r, ref float g, ref float b, ref float a)
        {
            r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            g = (float)Math.Pow(g, G_Gamma);
            b = (float)Math.Pow(b, G_Gamma);

            double max = Math.Max(r, Math.Max(g, b));

            var log2 = Math.Log(2.0);
            float n = (int)Math.Ceiling(Math.Log(max) / log2);//求最大值是 2的n 次方，

            if (n < -128)
            {
                n = -128;
            }
            if (n > 127)
            {
                n = 127;
            }
            var scale = (float)Math.Pow(2.0, n); //用2的N次方确定缩放系数

            //找到一个规整的值
            r = (float)(r / scale);
            g = (float)(g / scale);
            b = (float)(b / scale);
            if (r < 0.0)
            {
                r = 0.0f;
            }
            if (g < 0.0)
            {
                g = 0.0f;
            }
            if (b < 0.0)
            {
                b = 0.0f;
            }
            a = (n + 128) / 255.0f;

            //add log
            maxcolor = Math.Max(max, maxcolor);
        }

        static void srcrgbe_check(ref float r, ref float g, ref float b, ref float a)
        {
            srcrgbe(ref r, ref g, ref b, ref a);
            if (r < 0) r = 0;
            if (g < 0) g = 0;
            if (b < 0) b = 0;
            if (a < 0) a = 0;
            if (r > 1.0f) r = 1.0f;
            if (g > 1.0f) g = 1.0f;
            if (b > 1.0f) b = 1.0f;
            if (a > 1.0f) a = 1.0f;
            r = ((int)(r * 255.0)) / 255.0f;
            g = ((int)(g * 255.0)) / 255.0f;
            b = ((int)(b * 255.0)) / 255.0f;
            a = ((int)(a * 255.0)) / 255.0f;
            var power = (float)Math.Pow(2.0, ((a * 255.0) - 128.0));// * 2.0f;
            r *= power;
            g *= power;
            b *= power;
            a = 1.0f;
        }

        //线性方案
        static void rgbefix(ref float r, ref float g, ref float b, ref float a)
        {
            r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            g = (float)Math.Pow(g, G_Gamma);
            b = (float)Math.Pow(b, G_Gamma);

            float max = Math.Max(r, Math.Max(g, b));
            max = (float)Math.Ceiling(max);
            if (max > 128) max = 128;
            r = (float)(r / max);
            g = (float)(g / max);
            b = (float)(b / max);

            a = max / 128.0f;

        }
        static void rgbefix_check(ref float r, ref float g, ref float b, ref float a)
        {
            rgbefix(ref r, ref g, ref b, ref a);
            if (r < 0) r = 0;
            if (g < 0) g = 0;
            if (b < 0) b = 0;
            if (a < 0) a = 0;
            if (r > 1.0f) r = 1.0f;
            if (g > 1.0f) g = 1.0f;
            if (b > 1.0f) b = 1.0f;
            if (a > 1.0f) a = 1.0f;
            r = ((int)(r * 255.0)) / 255.0f;
            g = ((int)(g * 255.0)) / 255.0f;
            b = ((int)(b * 255.0)) / 255.0f;
            a = ((int)(a * 255.0)) / 255.0f;

            var power = (float)(int)(a * 128.0);// * 2.0f;
            r *= power;
            g *= power;
            b *= power;
            a = 1.0f;

        }

        //降低指数空间方案2的 -7 ~ +8 次方够大
        static void rgbefix_2(ref float r, ref float g, ref float b, ref float a)
        {
            r = (float)Math.Pow(r, G_Gamma);//这是个gamma矫正，tone个毛线
            g = (float)Math.Pow(g, G_Gamma);
            b = (float)Math.Pow(b, G_Gamma);


            double max = Math.Max(r, Math.Max(g, b));
            var log2 = Math.Log(2.0);
            float n = (float)(Math.Log(max) / log2);//求最大值是 2的n 次方，
            if (n > 8)
                n = 8;
            if (n < 0)
                n = 0;
            var scale = (float)Math.Pow(2.0, n); //用2的N次方确定缩放系数

            r = (float)(r / scale);
            g = (float)(g / scale);
            b = (float)(b / scale);

            a = (n + 0) / 8.0f;

        }
        static void rgbefix2_check(ref float r, ref float g, ref float b, ref float a)
        {
            rgbefix_2(ref r, ref g, ref b, ref a);
            if (r < 0) r = 0;
            if (g < 0) g = 0;
            if (b < 0) b = 0;
            if (a < 0) a = 0;
            if (r > 1.0f) r = 1.0f;
            if (g > 1.0f) g = 1.0f;
            if (b > 1.0f) b = 1.0f;
            if (a > 1.0f) a = 1.0f;
            r = ((int)(r * 255.0)) / 255.0f;
            g = ((int)(g * 255.0)) / 255.0f;
            b = ((int)(b * 255.0)) / 255.0f;
            a = ((int)(a * 255.0)) / 255.0f;


            var power = (float)Math.Pow(2.0, a *8.0f);
            r *= power;
            g *= power;
            b *= power;
            a = 1.0f;
        }
    }
}
